﻿#include "BCQmlRenderView.h"
#include "VideoRenderOpenGL.h"
#include <QPainter>
#include <QQuickWindow>
#include <QThread>

BCQmlRenderView::BCQmlRenderView(QQuickItem *parent)
    : QQuickPaintedItem(parent)
    , m_render(new VideoRenderOpenGL(width(), height()))
    , m_frame(nullptr)
    , m_rotation(0)
    , m_mirrored(false)
{
    m_frame = av_frame_alloc();
    setRenderTarget(FramebufferObject);
    connect(this, SIGNAL(frameDelivered()), this, SLOT(renderFrame()));
    connect(this, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(handleWindowChanged(QQuickWindow*)));
    setViewProperties(0,1,0,0,1);
}

BCQmlRenderView::~BCQmlRenderView()
{
    cleanup();
}

int BCQmlRenderView::setViewProperties(int zOrder, float left, float top, float right, float bottom)
{
    if (this == nullptr) {
        return 0;
    }
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_render)
        return m_render->setStreamProperties(zOrder, left, top, right, bottom);
    return -1;
}

void BCQmlRenderView::handleWindowChanged(QQuickWindow *win)
{
    if (win) {
        connect(win, SIGNAL(sceneGraphInvalidated()), this, SLOT(cleanup()), Qt::DirectConnection);
    }
}

void BCQmlRenderView::cleanup()
{
    {
        std::lock_guard<std::mutex> lock(m_mutex);

        if (m_frame) {
            av_frame_free(&m_frame);
        }
    }
    m_render.reset();
    emit widgetInvalidated();
}

void BCQmlRenderView::renderFrame()
{
    update();
}

int BCQmlRenderView::deliverFrame(AVFrame *frame, int rotation, bool mirrored)
{
    //    if (frame.IsZeroSize())
    //        return -1;
//    qDebug() << "deliverFrame thread" << QThread::currentThreadId();
    int r = 0;
    {
        std::lock_guard<std::mutex> lock(m_mutex);

        m_rotation = rotation;
        m_mirrored = mirrored;
        if (m_frame)
            av_frame_free(&m_frame);
        m_frame = av_frame_clone(frame);
    }

    //notify the render thread to redraw the incoming frame
    emit frameDelivered();

    return r;
}

void BCQmlRenderView::paint(QPainter *painter)
{
    if (!m_render)
        return;

//    qDebug() << "paint thread" << QThread::currentThreadId();
    painter->beginNativePainting();

    if (!m_render->isInitialized())
        m_render->initialize(width(), height());

    {
        std::lock_guard<std::mutex> lock(m_mutex);

        m_render->setFrameInfo(m_rotation, m_mirrored);
        if (m_frame)
            m_render->renderFrame(m_frame);
    }

    painter->endNativePainting();
}

void BCQmlRenderView::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry)
{
    if (newGeometry.width() != oldGeometry.width() ||
            newGeometry.height() != oldGeometry.height())
    {
        m_render->setSize(newGeometry.width(), newGeometry.height());
        emit viewSizeChanged(newGeometry.width(), newGeometry.height());
    }
    QQuickPaintedItem::geometryChanged(newGeometry, oldGeometry);
}
